﻿using System.Diagnostics;
using TPOJ.Core.Utils;

namespace TPOJ.Core
{
    /// <summary>
    /// The Compiler of the judge engine.
    /// It compiles the submission source code to binary file.
    /// </summary>
    class Compiler
    {
        private const int WAIT_MILLISECONDS = 60000;
        private Result result = new Result();
        private string fileName, args;

        public string InputPath { get; set; }

        public string OutputPath { get; set; }

        public Language Language { get; set; }

        /// <summary>
        /// Create a compiler with given params.
        /// </summary>
        /// <param name="inputPath">The source code file path</param>
        /// <param name="outputPath">The binary file path</param>
        /// <param name="language">The programming language used</param>
        public Compiler(string inputPath, string outputPath, Language language)
        {
            this.InputPath = inputPath;
            this.OutputPath = outputPath;
            this.Language = language;
            ParseCommandLineArgs();
        }

        /// <summary>
        /// Parse the language compile command line to initialise compile process file name and arguements.
        /// </summary>
        private void ParseCommandLineArgs()
        {
            string cmd = this.Language.CompileCommandLine.Replace("%1", this.InputPath)
                                            .Replace("%2",this.OutputPath);
            int index = cmd.IndexOf(' ');
            this.fileName = cmd.Substring(0, index);
            this.args = cmd.Substring(index,cmd.Length - index);
        }


        /// <summary>
        /// Run the compiler.
        /// </summary>
        /// <returns>The compiling result</returns>
        public Result Compile()
        {
            result.ResultType = ResultType.CompileError;

            ProcessStartInfo startInfo = new ProcessStartInfo(this.fileName);
            startInfo.Arguments = this.args;
            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
            startInfo.CreateNoWindow = true;
            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardOutput = true;

            Process p = Process.Start(startInfo);
            if (p.WaitForExit(WAIT_MILLISECONDS))
            {
                result.ExitCode = p.ExitCode;
                result.ErrorMessage = p.StandardOutput.ReadToEnd().FormatCompileWarning();
            }
            else
            {
                p.Kill();
                result.ExitCode = int.MinValue;
                result.ErrorMessage = "Compile System Failure.";
            }
            return result;
        }
    }
}
